package com.example.demo.service;

import com.example.demo.dto.ResultDto;
import com.example.demo.dto.ResultDto.ResultCode;
import com.example.demo.dto.request.ProductEditReqDto;
import com.example.demo.dto.request.ProductInsertReq;
import com.example.demo.dto.request.ProductQueryReqDto;
import com.example.demo.dto.response.ProductDetailResDto;
import com.example.demo.jooq.meta.tables.records.ProductRecord;
import com.example.demo.utils.ConditionBuilder;
import com.example.demo.utils.JqBuilder;
import lombok.extern.slf4j.Slf4j;
import org.jooq.DSLContext;
import org.jooq.Record1;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;

import static com.example.demo.jooq.meta.Tables.BRAND;
import static com.example.demo.jooq.meta.Tables.PRODUCT;
import static com.example.demo.jooq.meta.Tables.CATEGORY;

/**
 * @author Scott Yan
 * @date 2020/07/08
 */
@Service
@Slf4j
public class ProductService {

    @Resource
    private JqBuilder jqBuilder;

    public ResultDto query(ProductQueryReqDto dto, Pageable pageable) {
        var condition = jqBuilder.getConditionBuilder()
                .eq(!StringUtils.isEmpty(dto.getCode()), PRODUCT.CODE, dto.getCode())
                .like(!StringUtils.isEmpty(dto.getCode()), PRODUCT.NAME, dto.getName())
                .like(!StringUtils.isEmpty(dto.getBrandName()), BRAND.NAME, dto.getBrandName())
                .like(!StringUtils.isEmpty(dto.getCategoryName()),CATEGORY.NAME,dto.getCategoryName())
                .toCondition();

        try {
            var ctx = jqBuilder.getContext();

            var select = ctx
                    .select(PRODUCT.NAME, PRODUCT.CODE, BRAND.NAME.as("brandName"), CATEGORY.NAME.as("categoryName"))
                    .from(PRODUCT)
                    .leftJoin(BRAND).on(PRODUCT.BRAND_ID.eq(BRAND.ID))
                    .leftJoin(CATEGORY).on(PRODUCT.CATEGORY_ID.eq(CATEGORY.ID))
                    .where(condition);

            log.debug(select.toString());

            var cnt = ctx.fetchCount(select);

            var data = select

                    .orderBy(jqBuilder.getSortFields(pageable.getSort(), PRODUCT))

                    .limit(pageable.getPageSize())

                    .offset(pageable.getOffset())

                    .fetchInto(ProductDetailResDto.class);

            return ResultDto.success(/*new PageImpl<>(data, pageable, cnt)*/data);

        }catch (Exception ex){
            return ResultDto.error(ResultCode.DATABASE_ERROR, ex.getMessage());
        }

    }

    public ResultDto update(ProductEditReqDto dto) {
        var ctx = jqBuilder.getContext();
        var isInsert = true;
        if (dto.getId() != null) {
            var entity = ctx.fetchOne(PRODUCT, PRODUCT.ID.eq(dto.getId()));
            if (entity != null) {
                if (!StringUtils.isEmpty(dto.getCode())) {
                    entity.setCode(dto.getCode());
                }
                if (!StringUtils.isEmpty(dto.getName())) {
                    entity.setName(dto.getName());
                }
                entity.store();
                return ResultDto.success();
            }
        }

        if (StringUtils.isEmpty(dto.getCode())) {

            return ResultDto.error(ResultCode.ARGUMENT_INVALID, "code cannot be null");

        } else if (StringUtils.isEmpty(dto.getName())) {

            return ResultDto.error(ResultCode.ARGUMENT_INVALID, "'name cannot be null");

        }
        var newRecord = ctx.newRecord(PRODUCT);

        newRecord.setCode(dto.getCode());

        newRecord.setName(dto.getName());

        newRecord.setBrandId(dto.getBrandId());

        newRecord.setCategoryId(dto.getCategoryId()); newRecord.store();

        return ResultDto.success();

    }

    public ResultDto insert(ProductInsertReq product) {
        if (StringUtils.isEmpty(product.getBrandName()) || StringUtils.isEmpty(product.getCategoryName()) || StringUtils.isEmpty(product.getName()))
            return ResultDto.error(ResultCode.ARGUMENT_INVALID,"name could not be null");
        DSLContext context = jqBuilder.getContext();
        ProductRecord goal = context.newRecord(PRODUCT);
        var brandId = context.select(BRAND.ID).from(BRAND).where(jqBuilder.getConditionBuilder().eq(true,BRAND.NAME,product.getBrandName()).toCondition()).fetchOne().value1();
        var categoryId = context.select(CATEGORY.ID).from(CATEGORY).where(jqBuilder.getConditionBuilder().eq(true,CATEGORY.NAME,product.getCategoryName()).toCondition()).fetchOne().value1();
        goal.setName(product.getName());
        goal.setBrandId(brandId);
        goal.setCategoryId(categoryId);
        int store = goal.store();
        return ResultDto.success(store);

    }
}
